use std::str::FromStr;

use serde::{Serialize, Deserialize};
use reqwest::Client;
use crate::db::db_select;
use crate::{api::get_user_token::get_user_token, db::db_select::db_select};
use crate::api::get_device_token::get_device_token;
use crate::api::get_jwt::JWT_INSTANCE;
use crate::api::get_signature::get_signature;
use crate::db::db_insert::{self, db_insert};
use anyhow::{anyhow, Result};
use chrono::{DateTime, Utc};

/* 发送结构体 */
#[derive(Serialize, Deserialize, Debug)]
struct payload {
    AccessToken: String,
    AppId: String,
    DeviceToken: String,
    SandBox: String,
    SiteName: String,
    UseModernGamertag: bool,
    ProofKey: ProofKey,
}
#[derive(Serialize, Deserialize, Debug)]
struct ProofKey {
    r#use: String,
    alg: String,
    kty: String,
    crv: String,
    x: String,
    y: String,
}
/* 接收结构体 */
#[derive(Debug, Serialize, Deserialize)]
struct XboxAuthResponse {
    DeviceToken: String,
    TitleToken: TitleToken,
    UserToken: UserToken,
    AuthorizationToken: AuthorizationToken,
    WebPage: String,
    Sandbox: String,
    UseModernGamertag: bool,
    Flow: String,
}

#[derive(Debug, Serialize, Deserialize)]
struct TitleToken {
    DisplayClaims: TitleDisplayClaims,
    IssueInstant: String,
    NotAfter: String,
    Token: String,
}

#[derive(Debug, Serialize, Deserialize)]
struct UserToken {
    DisplayClaims: UserDisplayClaims,
    IssueInstant: String,
    NotAfter: String,
    Token: String,
}

#[derive(Debug, Serialize, Deserialize)]
struct AuthorizationToken {
    DisplayClaims: AuthorizationDisplayClaims,
    IssueInstant: String,
    NotAfter: String,
    Token: String,
}

#[derive(Debug, Serialize, Deserialize)]
struct TitleDisplayClaims {
    xti: XtiClaims,
}

#[derive(Debug, Serialize, Deserialize)]
struct XtiClaims {
    tid: String,
}

#[derive(Debug, Serialize, Deserialize)]
struct UserDisplayClaims {
    xui: Vec<XuiUserClaims>,
}

#[derive(Debug, Serialize, Deserialize)]
struct XuiUserClaims {
    uhs: String,
}

#[derive(Debug, Serialize, Deserialize)]
struct AuthorizationDisplayClaims {
    xui: Vec<XuiAuthorizationClaims>,
}

#[derive(Debug, Serialize, Deserialize)]
struct XuiAuthorizationClaims {
    gtg: String,
    xid: String,
    uhs: String,
    mgt: String,
    umg: String,
    agg: String,
    usr: String,
    prv: String,
}

pub async fn get_sisu_token() -> Result<String> {
    {
        // 检查数据库的sisu_token是否过期
        if let Ok(not_after) = db_select("sisu_token_not_after").await {
            let not_after:DateTime<Utc> = DateTime::from_str(&not_after.value).unwrap();
            let now = Utc::now();
            if(now < not_after){
                // 没过期，直接返回
                return Ok(db_select("sisu_token").await.unwrap().value);
            }
        }
    }
    get_sisu_and_title_token().await.unwrap();
    return Ok(db_select("sisu_token").await.unwrap().value);

}
pub async fn get_title_token() -> Result<String> {
    {
        // 检查数据库的sisu_token是否过期
        if let Ok(not_after) = db_select("title_token_not_after").await {
            let not_after:DateTime<Utc> = DateTime::from_str(&not_after.value).unwrap();
            let now = Utc::now();
            if(now < not_after){
                // 没过期，直接返回
                return Ok(db_select("title_token").await.unwrap().value);
            }
        }
    }
    get_sisu_and_title_token().await.unwrap();
    return Ok(db_select("title_token").await.unwrap().value);
}
pub async fn get_sisu_device_token() -> Result<String> {
    if let Ok(sisu_device_token) = db_select("sisu_device_token").await {
        return Ok(sisu_device_token.value);
    } else {
        get_sisu_and_title_token().await.unwrap();
        return Ok(db_select("sisu_device_token").await.unwrap().value);
    }
}
pub async fn get_sisu_user_token() -> Result<String> {
    {
        if let Ok(sisu_user_token_not_after) = db_select("sisu_user_token_not_after").await {
            let not_after:DateTime<Utc> = DateTime::from_str(&sisu_user_token_not_after.value).unwrap();
            let now = Utc::now();
            if(now < not_after){
                // 没过期，直接返回
                return Ok(db_select("sisu_user_token").await.unwrap().value);
            }
        }
    }
    get_sisu_and_title_token().await.unwrap();
    return Ok(db_select("sisu_user_token").await.unwrap().value);
}
// 用于过期时重新获取token
async fn get_sisu_and_title_token() -> Result<()> {
    let access_token = format!("t={}", get_user_token().await.unwrap());
    let payload = payload {
        AccessToken: access_token, // 这里是用户token
        AppId: "000000004c20a908".to_string(),
        DeviceToken: get_device_token().await.unwrap(),
        SandBox: "RETAIL".to_string(),
        SiteName: "user.auth.xboxlive.com".to_string(),
        UseModernGamertag: true,
        ProofKey: ProofKey {
            r#use: "sig".to_string(),
            alg: "ES256".to_string(),
            kty: "EC".to_string(),
            crv: "P-256".to_string(),
            x: JWT_INSTANCE.get().unwrap().x_b64.clone(),
            y: JWT_INSTANCE.get().unwrap().y_b64.clone(),
        }
    };
    let body = serde_json::to_string(&payload).unwrap();

    let client = Client::new();
    let response = client.post("https://sisu.xboxlive.com/authorize")
        .header("x-xbl-contract-version", "1")
        .header("Cache-Control", "no-store, must-revalidate, no-cache")
        .header("Signature", get_signature("https://sisu.xboxlive.com/authorize", "", &body))
        .body(body)
        .send().await.unwrap();

    let response_code = response.status().as_u16();
    let response_body = response.text().await.unwrap();

    // println!("sisu_token_response body: {}", response_body);
    match response_code {
        200 => {
            let response_structure:XboxAuthResponse = serde_json::from_str(&response_body).unwrap();
            db_insert("title_token", &response_structure.TitleToken.Token).await.unwrap();
            db_insert("title_token_not_after", &response_structure.TitleToken.NotAfter).await.unwrap();
            db_insert("sisu_token", &response_structure.AuthorizationToken.Token).await.unwrap();
            db_insert("sisu_token_not_after", &response_structure.AuthorizationToken.NotAfter).await.unwrap();
            db_insert("sisu_device_token", &response_structure.DeviceToken).await.unwrap();
            db_insert("sisu_user_token", &response_structure.UserToken.Token).await.unwrap();
            db_insert("sisu_user_token_not_after", &response_structure.UserToken.NotAfter).await.unwrap();
            return Ok(());
        }
        _ => {
            return Err(anyhow!("failed to get sisu and title token, response code: {}",response_code));
        }
    }
}